package com.mc.lp.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.Resource;
import javax.transaction.Transactional;

import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.mc.lp.database.dao.IAcademicRecordDAO;
import com.mc.lp.database.entity.AcademicRecordEntity;
import com.mc.lp.database.entity.SubjectEntity;
import com.mc.lp.database.entity.helper.AcademicRecordHelper;
import com.mc.lp.database.exception.ConcurrentAccessException;
import com.mc.lp.database.service.IAttachmentService;
import com.mc.lp.service.AcademicRecordService;
import com.mc.lp.service.MicroCampusAbstractService;
import com.mc.lp.shared.util.constants.ResponseStatus;
import com.mc.lp.shared.vo.AcademicRecordVO;
import com.mc.lp.shared.vo.EntitySaveResponse;
import com.mc.lp.shared.vo.IValueObject;
import com.mc.lp.shared.vo.SearchCriteriaVO;
import com.mc.lp.shared.vo.ServiceResponse;
import com.mc.lp.shared.vo.StudentRecordVO;
import com.mc.lp.shared.vo.ValueObjectList;

/*
 * @author aphanda
 * @date Sep 14, 2014
 * @time 2:03:41 AM
 */

/**
 * @author aphanda
 * this method will return each record wise saved information 
 */
@Service
public class AcademicRecordServiceImpl extends
		MicroCampusAbstractService<AcademicRecordServiceImpl> implements AcademicRecordService {
	
	@Resource
	IAcademicRecordDAO academicRecordDAO;
	
	@Resource
	IAttachmentService attachmentService;
	
	AcademicRecordHelper academicRecordHelper = new AcademicRecordHelper();
	
	/* (non-Javadoc)
	 * @see com.mc.lp.service.AcademicRecordService#saveAcademics()
	 * returns ServiceResponse object on successful run
	 */
	@Transactional
	public IValueObject saveAcademics(StudentRecordVO studentRecordVO) {

	ArrayList<EntitySaveResponse> saveResponse = new ArrayList<EntitySaveResponse>();
	ServiceResponse<EntitySaveResponse> serviceResponse = new ServiceResponse<EntitySaveResponse>();
	AcademicRecordHelper helper = new AcademicRecordHelper();
		for (AcademicRecordVO vo : studentRecordVO.getStudentAcademics()) {
			EntitySaveResponse response = new EntitySaveResponse(vo.getSid(), "StudenAcademic");
			
			AcademicRecordEntity dbRecord = new AcademicRecordEntity();
			AcademicRecordEntity academic = helper.getEntity(vo);
			academic.setStudentEntity(studentRecordVO.getSearchCriteria().getStudentEntityId());

			SubjectEntity subjectEntity = new SubjectEntity();
			subjectEntity.setId(vo.getSubjectId());
			academic.setSubject(subjectEntity);

			if (!vo.isNewRow()) {
				if (vo.getSid() != 0) {
					dbRecord = academicRecordDAO.findById(vo.getSid());
					// Delete the entity which is marked as deleted on UI
					if (vo.isRowDeleted()) {
							try {
								academicRecordDAO.delete(dbRecord);
								response.setStatus(ResponseStatus.SUCCESS);
								serviceResponse.setStatus(ResponseStatus.SUCCESS);
							} catch (DataAccessException e) {
								getLogger().error("saveAcademics()", e);
								response.setStatus(ResponseStatus.FAILED);
								response.setMsg(e.getMessage());
								
								serviceResponse.setStatus(ResponseStatus.FAILED);
								serviceResponse.setMsg(e.getMessage());
								
							} catch (ConcurrentAccessException e) {
								getLogger().error("saveAcademics()", e);
								response.setStatus(ResponseStatus.FAILED);
								response.setMsg(e.getMessage());
								serviceResponse.setStatus(ResponseStatus.FAILED);
								serviceResponse.setMsg(e.getMessage());
							}
						continue;
					}
					//AP this we need to do with reflection to avoid any kind or missed property situation.
					if (!dbRecord.equals(vo)) {
						try {
							academicRecordHelper.setEntity(vo, dbRecord);
							academicRecordDAO.saveOrUpdate(dbRecord);
							response.setStatus(ResponseStatus.SUCCESS);
							serviceResponse.setStatus(ResponseStatus.SUCCESS);
						} catch (DataAccessException e) {
							getLogger().error("saveAcademics()", e);
							response.setStatus(ResponseStatus.FAILED);
							response.setMsg(e.getMessage());
							serviceResponse.setStatus(ResponseStatus.FAILED);
							serviceResponse.setMsg(e.getMessage());
						} catch (ConcurrentAccessException e) {
							getLogger().error("saveAcademics()", e);
							response.setStatus(ResponseStatus.FAILED);
							response.setMsg(e.getMessage());
							serviceResponse.setStatus(ResponseStatus.FAILED);
							serviceResponse.setMsg(e.getMessage());
						}
					}
				}
			}else {
				academicRecordDAO.save(academic);
				response.setStatus(ResponseStatus.SUCCESS);
				serviceResponse.setStatus(ResponseStatus.SUCCESS);
			}
			//add response to list and send back to ui
			saveResponse.add(response);
		}
		
		serviceResponse.setResult(saveResponse);
		return serviceResponse;
	}

	/**
	 * return list of student records based on grade and term;
	 */
	@Transactional
	public ServiceResponse<AcademicRecordVO> getAcademicsRecordsByEntityIdTermGrade(StudentRecordVO studentRecordVO) {
		SearchCriteriaVO searchValue= studentRecordVO.getSearchCriteria();
		List<AcademicRecordVO> resultVoList = new ArrayList<AcademicRecordVO>();
		ServiceResponse<AcademicRecordVO> response = new ServiceResponse<AcademicRecordVO>();
		Long entityId=searchValue.getStudentEntityId();
		int gradeId=searchValue.getGradeId();
		int termId=searchValue.getTermId();
		getLogger().info("getAcademicsRecordsByGradeAndTerm : entityId:"+entityId +", gradeId :"+gradeId+", termId: "+termId);
		List<AcademicRecordEntity> searchedRecords=academicRecordDAO.fetchDetailsByEntityIdTermGrade(entityId,gradeId,termId);
		if(CollectionUtils.isEmpty(searchedRecords)){
			response.setStatus(ResponseStatus.NOT_FOUND);
			getLogger().info("getAcademicsRecordsByGradeAndTerm : No record found in db for given params");
		}else{
			getLogger().info("getAcademicsRecordsByGradeAndTerm : Total records found :"+ searchedRecords);
			for(AcademicRecordEntity entity: searchedRecords){
				AcademicRecordVO vo = academicRecordHelper.getVO(entity);
				resultVoList.add(vo);
			}
			//get attachments to be displayed on ui
			ValueObjectList fileList = attachmentService.getAttachmentsWithoutData(searchValue);
			response.setExtraInfo(fileList);
			response.setStatus(ResponseStatus.SUCCESS);
		}
		response.setResult(resultVoList);
		return response;		
	}

	public ValueObjectList getAcademicsByEntityId(StudentRecordVO studentRecordVO) {
		ValueObjectList list = new ValueObjectList();
		return list;
	}

	@Transactional
	public List<AcademicRecordVO> getAcademicsByEntityIdYear(Long entityId, int year, int limit) {
		// TODO Auto-generated method stub
		List<AcademicRecordVO> voList = new ArrayList<AcademicRecordVO>();
		List<AcademicRecordEntity> acadList = new ArrayList<AcademicRecordEntity>();
	
		acadList = academicRecordDAO.fetchDetailsByEntityIdYear(entityId, year, limit);

		for (AcademicRecordEntity entity : acadList) {
			voList.add(academicRecordHelper.getVO(entity));
		}
		return voList;
	}
	
	
	@Transactional
	public List<AcademicRecordVO> getAcademicsByEntityIdTerm(Long entityId, int year, int termId, int limit) {
		// TODO Auto-generated method stub
		List<AcademicRecordVO> voList = new ArrayList<AcademicRecordVO>();
		List<AcademicRecordEntity> acadList = new ArrayList<AcademicRecordEntity>();
	
		acadList = academicRecordDAO.fetchDetailsByEntityIdTerm(entityId, year, termId, limit);

		for (AcademicRecordEntity entity : acadList) {
			voList.add(academicRecordHelper.getVO(entity));
		}
		return voList;
	}

	@Transactional
	public List<AcademicRecordEntity> getAllAcademicsByStudentEntity(Long studentEntity) {
		
		return academicRecordDAO.getAllAcadsByStudentEntity(studentEntity);
	}
	
	@Transactional
	public List<AcademicRecordVO> getAcademicsByGrades(Long studentEntity,
			List<Integer> gradeValueList) {
		List<AcademicRecordVO> voList = new ArrayList<AcademicRecordVO>();
		List<AcademicRecordEntity> acadList = new ArrayList<AcademicRecordEntity>();

		acadList = academicRecordDAO.fetchAcademicsByGrades(studentEntity,  gradeValueList);
		for (AcademicRecordEntity entity : acadList) {
			voList.add(academicRecordHelper.getVO(entity));
		}
		return voList;
	}
	
	
	@Transactional
	public List<AcademicRecordVO> getAcademicsBySearchCriteriaForAdvancedGraph(SearchCriteriaVO crit){
		
		List<AcademicRecordVO> voList = new ArrayList<AcademicRecordVO>();
		List<AcademicRecordEntity> acadList = new ArrayList<AcademicRecordEntity>();

		acadList = academicRecordDAO.fetchAcademicsBySearchCriteriaForAdvancedGraph(crit);
		for (AcademicRecordEntity entity : acadList) {
			voList.add(academicRecordHelper.getVO(entity));
		}
		return voList;
		
	}

	@Transactional
	public List<AcademicRecordVO> getAcademicsByEntityIdGrade(Long entityId, int gradeId) {
		
		List<AcademicRecordVO> voList = new ArrayList<AcademicRecordVO>();
		List<AcademicRecordEntity> acadList = new ArrayList<AcademicRecordEntity>();

		acadList = academicRecordDAO.fetchAcademicsByGrades(entityId, new ArrayList<Integer>(Arrays.asList(gradeId)));
		for (AcademicRecordEntity entity : acadList) {
			voList.add(academicRecordHelper.getVO(entity));
		}
		return voList;
	}
}
